package com.yanfan.dlt698_45.frame;

import com.yanfan.dlt698_45.DLT698Utils;
import com.yanfan.dlt698_45.exception.DLT698_45TransportException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

/**
 * @author oliver foo
 * 0x68   |       0x00 0x00       | 0x00 | 0X00   |0x00 0x00 0x00 0x00 0x00 0x00 |  0x00  |0x00,0x00 |0x00| 0x00,0x00  |0x16
 * 固定68  | 排除0x68和0x16 的总长度 |控制码 |  地址特征 |    6位 地址（变长的一般6位）    | 客户机地 | 帧头校验   |数据 | 全部数据校验 | 固定 16
 * @date 2023/3/21 9:06
 */
abstract public class DLT698_45Frame {

    protected final byte[] address;

    /**
     * 地址类型
     * 0表示单地址
     * 1表示通配地址
     * 2表示组地址
     * 3表示广播地址
     */
    protected final byte addressType;


    public DLT698_45Frame(byte[] address, byte addressType) throws DLT698_45TransportException {
        if (address.length < 1) {
            throw new DLT698_45TransportException("Invalid address");
        }
        this.addressType = addressType;
        this.address = address;
    }


    public byte[] getAddress() {
        return address;
    }

    abstract public byte[] getObjectAddressDesc();

    /**
     * 传递方向
     * 0b 0 1: 客户机发起的请求
     * 0b 1 1: 服务器对客户机请求的响应
     *
     * @return
     */
    abstract public byte getDestination();

    /**
     * 0b001 链路连接管理（登录，心跳，退出登录）
     * 0b011 应用连接管理及数据交换服务
     *
     * @return
     */
    abstract public byte getFunctionCode();


    /**
     * 客户机地址
     * 0表示不关注客户机地址。
     *
     * @return
     */
    abstract public byte getClientAddress();


    /**
     * 有无后续报文
     * false: 没有
     * true:  有
     *
     * @return
     */
    abstract public boolean hasFollowFrame();

    /**
     * 获取报文总长度  两个byte
     *
     * @return
     */
    abstract int getFrameLength();


    protected abstract void writeImpl(ByteBuf buf);


    /**
     * 控制码
     *
     * @return
     */
    public byte getControlCode() {
        return DLT698Utils.getControlCode(getDestination(), hasFollowFrame(), getFunctionCode());
    }

    public byte[] getAddressByte() {
        return DLT698Utils.geAddressBytes(address, addressType);
    }


    final public void write(ByteBuf buf) {
        ByteBuf header = Unpooled.buffer();
        // 包总长
        header.writeShort(DLT698Utils.getHeaderLength(getFrameLength()));
        //控制位
        header.writeByte(getControlCode());
        // 服务器地址
        header.writeBytes(getAddressByte());
        //  客户机地址
        header.writeByte(getClientAddress());
        // 包头校验
        header.writeShort(DLT698Utils.computeFcs16(header));
        // 包头写入
        buf.writeBytes(header);
        writeImpl(buf);
    }


}
